<script lang="ts" setup>
import { bingWx } from '@/api/login'
import { validatePhone } from '@/utils/formvalidate'
import { useRouter } from 'vue-router'
import { useUserStore } from '@/store/modules/user'
import { useDraw } from '@/hooks/useDraw'
import { getComId, setComId } from '@/utils/cache/cookies'
import { ElMessage, FormInstance, FormRules } from 'element-plus'
import { computed, onBeforeUnmount, onMounted, reactive, ref, watch, watchEffect } from 'vue'
import dayjs from 'dayjs'
import { LoginSMSRequestData } from '@/api/login/types/login'
import { useSMS } from '@/hooks/useSMS'
// 登录类型状态，'standard'为普通登录，'qrcode'为二维码登录
const loginType = ref('qrcode')
const dialogVisible = ref<boolean>(false)
const router = useRouter()
interface FormState {
  form: LoginSMSRequestData
  isLoading: boolean
  rule: FormRules
  disable: boolean
}
const createFormState = (): FormState => {
  return reactive({
    form: {
      phoneNumber: '',
      code: '',
    },
    isLoading: false,
    disable: false,
    rule: {
      phoneNumber: [{ validator: validatePhone, trigger: 'blur' }],
      code: [{ required: true, message: '请输入验证码', trigger: 'blur' }],
    },
  })
}
// 创建两个独立的状态
const loginState = createFormState()
const bindingState = createFormState()
/** 表单基础逻辑 */
const formRef = ref<FormInstance | null>(null)
const bindingFormRef = ref<FormInstance | null>(null)
// 对于登录表单
const { sendSMSLabel: loginSendSMSLabel, handleSendSMS: loginHandleSendSMS } = useSMS(loginState)
// 对于绑定表单
const { sendSMSLabel: bindingSendSMSLabel, handleSendSMS: bindingHandleSendSMS } =
  useSMS(bindingState)
const LoginButtonLabel = computed(() => {
  if (loginState.isLoading) {
    return '登录中...'
  } else {
    return '登录'
  }
})
const BindingButtonLabel = computed(() => {
  if (bindingState.isLoading) {
    return '绑定中...'
  } else {
    return '绑定'
  }
})

const { appRef, calcRate, windowDraw, unWindowDraw } = useDraw()
/** 微信登录 */
const comId = ref(getComId() ?? '')
const websock = ref<WebSocket | null>(null)
const timeoutId = ref<number>(0)
const serverTimeoutId = ref<number>(0)
const disconnectTimeoutId = ref<number>(0)
const time = ref<number>(50000)
const lockReconnect = ref<boolean>(false) //是否真正建立连接
const openId = ref<string>('')
const websockstate = ref<boolean>(true)
const websocketonopen = () => {
  start()
}
const websocketonerror = () => {
  //错误连接websoket
  //重连
  comId.value = getComId() ?? ''
  //重连
  if (comId.value !== '') {
    reconnect()
  }
}
const websocketonmessage = (e: MessageEvent) => {
  //收到服务器信息，心跳重置
  reset()
  const info = JSON.parse(e.data)
  if (info.resultCode === undefined && info.resultCode === null) return
  if (info.resultCode === 0) {
    const param = info.resultData
    useUserStore()
      .wxLogin(param)
      .then(() => {
        // 重定向对象不存在则返回顶层路径
        websockstate.value = false
        router.replace({ path: '/home' })
      })
  } else if (info.resultCode === 404) {
    openId.value = info.resultData
    dialogVisible.value = true
    ElMessage({
      message: info.resultMessage,
      type: 'warning',
    })
    initWxLogin()
  } else {
    ElMessage({
      message: info.resultMessage,
      type: 'warning',
    })
    initWxLogin()
  }
}
const websocketclose = () => {
  //关闭websoket  当切换为表单登录
  comId.value = getComId() ?? ''
  //重连
  if (comId.value !== '') {
    reconnect()
  }
}
const reset = () => {
  //重置心跳
  //清除时间
  clearTimeout(timeoutId.value)
  clearTimeout(serverTimeoutId.value)
  //重启心跳
  start()
}
const start = () => {
  clearTimeout(timeoutId.value)
  clearTimeout(serverTimeoutId.value)
  timeoutId.value = +setTimeout(() => {
    if (comId.value != '') {
      //这里发送一个心跳，后端收到后，返回一个心跳消息，
      if (websock.value?.readyState == 1) {
        //如果连接正常
        websock.value?.send(JSON.stringify({ comId: comId.value }))
      } else {
        //否则重连
        reconnect()
      }
    } else {
      websock.value?.close()
    }
    serverTimeoutId.value = +setTimeout(() => {
      websock.value?.close()
    }, time.value)
  }, time.value)
}
const reconnect = () => {
  if (lockReconnect.value) return
  if (websock.value?.readyState !== 1) {
    lockReconnect.value = true
    disconnectTimeoutId.value = +setTimeout(() => {
      initWebSocket()
      lockReconnect.value = false
    }, 2000)
  }
}
const loadWxLoginScript = () => {
  return new Promise<void>((resolve, reject) => {
    if (window.WxLogin) {
      resolve() // 已加载
    } else {
      const script = document.createElement('script')
      script.src = 'https://res.wx.qq.com/connect/zh_CN/htmledition/js/wxLogin.js' // 替换为实际路径
      script.onload = () => resolve()
      script.onerror = (err) => reject(err)
      document.body.appendChild(script)
    }
  })
}

const initWxLogin = async () => {
  try {
    await loadWxLoginScript()
    const WxLogin = window['WxLogin'] // 确保 WxLogin 可用
    const wxLoginInstance = new WxLogin({
      self_redirect: true,
      id: 'qrcode_container',
      appid: 'wxb59419d4437af40d',
      scope: 'snsapi_login',
      redirect_uri: encodeURIComponent(import.meta.env.VITE_API + 'WxCallBack'),
      state: comId.value,
      style: 'white',
      href: 'https://admin.xiaoyuchuxing.com/large_battery/wx.css',
      stylelite: '0',
    })
    console.log('WxLogin 初始化成功', wxLoginInstance)
  } catch (error) {
    console.error('WxLogin 加载失败:', error)
  }
}
const initWebSocket = () => {
  websock.value = new WebSocket(import.meta.env.VITE_WebSocket + 'token=' + comId.value)
  websock.value.onopen = websocketonopen
  websock.value.onerror = websocketonerror
  websock.value.onmessage = websocketonmessage
  websock.value.onclose = websocketclose
}
watch(loginType, (loginType) => {
  if (loginType === 'standard') {
    websockstate.value = false
    websock.value?.close()
    lockReconnect.value = true
  } else {
    websockstate.value = true
    initWxLogin()
    initWebSocket()
  }
})
watchEffect(() => {
  if (!websockstate.value) {
    lockReconnect.value = true
    websock.value?.close()
  }
})

const handleLogin = () => {
  sessionStorage.clear()
  formRef.value?.validate((valid) => {
    if (valid) {
      loginState.isLoading = true
      useUserStore()
        .login({
          ...loginState.form,
        })
        .then(() => {
          ElMessage.success('登录成功!')
          loginState.isLoading = false
          router.push('/')
        })
        .catch(() => {
          loginState.form.code = ''
        })
        .finally(() => {
          loginState.isLoading = false
        })
    }
  })
}
const handleBinding = () => {
  sessionStorage.clear()
  bindingFormRef.value?.validate((valid) => {
    if (valid) {
      bindingState.isLoading = true
      bingWx({
        ...bindingState.form,
        openId: openId.value,
        channel: 'Service',
      })
        .then(() => {
          ElMessage.success('绑定成功!')
          bindingState.isLoading = false
          dialogVisible.value = false
        })
        .finally(() => {
          bindingState.isLoading = false
        })
    }
  })
}

const resetBindingForm = () => {
  bindingFormRef.value?.resetFields()
  dialogVisible.value = false
}

onMounted(() => {
  windowDraw()
  calcRate()
  sessionStorage.clear()
  if (comId.value === '') {
    let code = '' // 在循环外声明code
    for (let i = 1; i <= 6; i++) {
      const num = Math.floor(Math.random() * 10)
      code += num.toString() // 确保num是字符串
    }
    comId.value = dayjs().format('YYYYMMDDHHmmss') + code
    setComId(comId.value)
  }
  initWxLogin()
  initWebSocket()
})
onBeforeUnmount(() => {
  unWindowDraw()
  //重置心跳
  //清除时间
  clearTimeout(timeoutId.value)
  clearTimeout(serverTimeoutId.value)
})
</script>

<template>
  <div class="login-bg-container" ref="appRef">
    <div class="login-form-container">
      <div class="login-type-switch">
        <div :class="{ active: loginType === 'qrcode' }" @click="loginType = 'qrcode'">
          二维码登录
        </div>
        <div :class="{ active: loginType === 'standard' }" @click="loginType = 'standard'">
          验证码登录
        </div>
      </div>
      <div v-show="loginType === 'qrcode'" mt-40 flex-1>
        <div id="qrcode_container" />
      </div>
      <div
        v-show="loginType === 'standard'"
        flex
        items-center
        justify-center
        w-full
        class="login-form"
      >
        <el-form :model="loginState.form" ref="formRef" :rules="loginState.rule" mt-40 size="large">
          <!-- 用户名输入 -->
          <el-form-item prop="phoneNumber">
            <el-input
              class="custom-input"
              v-model="loginState.form.phoneNumber"
              placeholder="请输入登录手机号"
            >
              <template #prefix>
                <SvgIcon class="custom-svg" name="phone" />
                <span class="text-[28px] mr-15">手机号</span>
                <el-divider direction="vertical" />
              </template>
            </el-input>
          </el-form-item>
          <!-- 密码输入 -->
          <el-form-item prop="code">
            <el-input
              class="custom-input"
              v-model="loginState.form.code"
              placeholder="请输入验证码"
            >
              <template #prefix>
                <SvgIcon class="custom-svg" name="password" />
                <span class="text-[28px] mr-15">验证码</span>
                <el-divider direction="vertical" />
              </template>
              <template #suffix>
                <el-button
                  class="custom-send-sms-button"
                  plain
                  @click="loginHandleSendSMS(formRef)"
                  :disabled="loginState.disable"
                  v-html="loginSendSMSLabel"
                />
              </template>
            </el-input>
          </el-form-item>
          <!-- 登录按钮 -->
          <el-form-item>
            <div w-full flex items-center justify-center>
              <el-button
                type="primary"
                @click="handleLogin"
                :loading="loginState.isLoading"
                class="custom-login-button"
              >
                <div>
                  {{ LoginButtonLabel }}
                </div>
              </el-button>
            </div>
          </el-form-item>
        </el-form>
      </div>
      <el-dialog v-model="dialogVisible" class="bing-form-dialog" top="20%" align-center center>
        <el-form
          :model="bindingState.form"
          ref="bindingFormRef"
          :rules="bindingState.rule"
          size="large"
        >
          <!-- 用户名输入 -->
          <el-form-item prop="phoneNumber">
            <el-input
              v-model="bindingState.form.phoneNumber"
              class="custom-bg-input"
              placeholder="请输入登录手机号"
            >
              <template #prefix>
                <SvgIcon class="custom-svg" name="phone" />
                <span class="text-[28px] mr-15">手机号</span>
                <el-divider direction="vertical" />
              </template>
            </el-input>
          </el-form-item>
          <!-- 密码输入 -->
          <el-form-item prop="code">
            <el-input
              v-model="bindingState.form.code"
              class="custom-bg-input"
              placeholder="请输入验证码"
              show-password
            >
              <template #prefix>
                <SvgIcon class="custom-svg" name="password" />
                <span class="text-[28px] mr-15">验证码</span>
                <el-divider direction="vertical" />
              </template>
              <template #suffix>
                <el-button
                  class="custom-send-sms-button"
                  link
                  @click="bindingHandleSendSMS(bindingFormRef)"
                  :disabled="bindingState.disable"
                  v-html="bindingSendSMSLabel"
                />
              </template>
            </el-input>
          </el-form-item>
        </el-form>
        <template #footer>
          <div class="h-[50%]">
            <el-button plain @click="resetBindingForm" class="bind-login-button">
              <div>取消</div>
            </el-button>
            <el-button
              type="primary"
              @click="handleBinding"
              class="bind-login-button"
              :loading="bindingState.isLoading"
            >
              <div>{{ BindingButtonLabel }}</div>
            </el-button>
          </div>
        </template>
      </el-dialog>
    </div>
  </div>
</template>

<style scoped lang="scss">
.login-bg-container {
  background-image: url(/src/assets/images/login-bg.png);
  width: 3840px;
  height: 2160px;
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  transform-origin: left top;
  display: flex;
  justify-content: center;
  align-items: center;
}
.login-form-container {
  background-image: url(/src/assets/images/form-bg.png);
  background-size: contain;
  background-position: center;
  width: 1114px;
  height: 856px;
  display: flex;
  flex-direction: column;
  padding: 200px 100px 60px;
}
.login-type-switch {
  display: flex;
  align-items: center;
  justify-content: center;
}
.login-type-switch div {
  cursor: pointer;
  line-height: 38px;
  font-size: 32px;
  font-weight: 400;
  color: var(--xy-white-color);
  position: relative; /* Required for absolute positioning of ::after */
  padding: 15px;
}
.login-type-switch div:last-child {
  margin-left: 100px;
}
.login-type-switch .active {
  font-weight: 500;
  background: linear-gradient(270deg, rgba(0, 73, 134, 0) 0%, rgba(69, 170, 255, 0.8) 100%);
}
.login-form {
  form {
    width: 80%;
  }
}
:deep(.custom-input .el-input__wrapper) {
  background: linear-gradient(90deg, #45aaff 0%, rgba(41, 102, 153, 0) 100%);
  padding: 1px 15px 1px 68px;
  box-shadow: none;
}
:deep(.el-input__prefix) {
  color: var(--xy-white-color);
}
:deep(.el-input--large .el-input__inner) {
  --el-input-inner-height: calc(92px - 2px);
  color: #9bc7ff;
}
.el-input--large {
  font-size: 26px;
}
.svg-icon.custom-svg {
  width: 32px;
  height: 32px;
  margin-right: 25px;
}
:deep(.el-divider--vertical) {
  border-left: 1px var(--el-border-color) var(--el-border-style);
  display: inline-block;
  height: 1em;
  margin: 0 24px;
  position: relative;
  vertical-align: middle;
  width: 1px;
}
:deep(input::placeholder) {
  font-size: 26px;
  color: #9bc7ff;
  line-height: 30px;
}
:deep(.custom-button--plain) {
  --el-button-bg-color: rgba(69, 170, 255, 0.1);
  --el-button-text-color: #9bc7ff;
  --el-button-border-color: #45aaff;
  --el-button-hover-text-color: var(--el-color-white);
  --el-button-hover-bg-color: #45aaff;
  --el-button-hover-border-color: #45aaff;
  --el-button-active-bg-color: rgb(128, 163, 208);
  --el-button-active-text-color: var(--el-color-white);
  --el-button-active-border-color: rgb(128, 163, 208);
  font-size: 26px;
  padding: 16px 20px;
  --el-button-size: 64px;
}
:deep(.custom-input .el-input__wrapper) {
  background-image: url(/src/assets/images/login-input-bg.png);
  background-size: cover;
  box-shadow: none;
  background-repeat: no-repeat;
  background-color: transparent;
}

:deep(.custom-login-button) {
  --el-button-size: 86px;
  width: 60%;
  font-size: 32px;
  margin-top: 64px;
  transform: skewX(-35deg);
  position: relative;
  will-change: transform;
}
:deep(.custom-login-button div) {
  transform: skewX(35deg);
  will-change: transform;
}
:deep(.custom-login-button::before) {
  content: '';
  width: 64px;
  height: 86px;
  position: absolute;
  left: -70px;
  top: 0;
  background: linear-gradient(
    to right,
    rgba(74, 155, 245, 0.4) 0,
    rgba(74, 155, 245, 0.4) 18px,
    transparent 18px,
    transparent 23px,
    rgba(74, 155, 245, 0.6) 23px,
    rgba(74, 155, 245, 0.6) 41px,
    transparent 41px,
    transparent 46px,
    rgba(74, 155, 245, 1) 46px,
    rgba(74, 155, 245, 1) 64px
  );
}
:deep(.custom-login-button::after) {
  content: '';
  width: 64px;
  height: 86px;
  position: absolute;
  right: -70px;
  bottom: 0;
  background: linear-gradient(
    to right,
    rgba(74, 155, 245, 1) 0,
    rgba(74, 155, 245, 1) 18px,
    transparent 18px,
    transparent 23px,
    rgba(74, 155, 245, 0.6) 23px,
    rgba(74, 155, 245, 0.6) 41px,
    transparent 41px,
    transparent 46px,
    rgba(74, 155, 245, 0.4) 46px,
    rgba(74, 155, 245, 0.4) 64px
  );
}
:deep(.el-form-item__error) {
  color: var(--el-color-danger);
  font-size: 20px;
  left: 0;
  line-height: 1;
  padding-top: 4px;
  position: absolute;
  top: 100%;
}
:deep(.custom-send-sms-button) {
  background-color: transparent;
  border: 1px solid rgba(69, 170, 255, 1);
  font-size: 26px;
  padding: 16px 20px;
  --el-button-size: 64px;
  color: rgba(155, 199, 255, 1);
}
:deep(.custom-send-sms-button:hover) {
  color: #fff;
  background-color: transparent;
  border: 1px solid rgba(69, 170, 255, 1);
}
:deep(.el-form-item--large) {
  --font-size: 14px;
  --el-form-label-font-size: var(--font-size);
  margin-bottom: 30px;
}
</style>
